﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ReadeAssetManager
{
    public partial class ucAssetsTree : UserControl
    {
        AMSServiceRef.User _user;
        delegateReturnObject _returnobj;
        DateTime _lastMouseDown;
        bool _preventExpand;

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="CurrentUser">[AMSServiceRef.User] The current application user.</param>
        /// <param name="ReturnObjectMethod">[delegateReturnObject] The method delegate from the
        /// frmMain userform.  This method passes objects back to frmMain, which then opens the
        /// appropriate userform to display the object.</param>
        public ucAssetsTree(AMSServiceRef.User CurrentUser, delegateReturnObject ReturnObjectMethod)
        {
            InitializeComponent();

            _lastMouseDown = DateTime.Now;
            _preventExpand = false;

            if (CurrentUser != null)
            {
                _user = CurrentUser;
                _returnobj = ReturnObjectMethod;
                LoadTreeView();
                tvAssets.ExpandAll();
                //tvAssets.ContextMenu = BuildContextMenu();
            }
            else
            {
                tvAssets.Nodes.Add(new TreeNode("Not logged in."));
            }
        }

        /// <summary>
        /// LoadTreeView
        /// Loads all the asset and domain records to the tree view.
        /// </summary>
        private void LoadTreeView()
        {
            if (_user.Assets == null)
                _user.Assets = new List<AMSServiceRef.Asset>();

            foreach (AMSServiceRef.Asset asset in _user.Assets)
            {
                TreeNode tn = new TreeNode(asset.Name, GetAssetChildren(asset));
                tn.Tag = asset;

                tvAssets.Nodes.Add(tn);
            }
        }

        /// <summary>
        /// BuildContextMenu
        /// Creates a ContextMenu to be attached to the treeview.  I was experiencing a lot of
        /// memory access errors after I implemented this feature.  I no longer use it, but in
        /// case I ever do figure out what went wrong, this would be a preferred way to display
        /// options.
        /// </summary>
        /// <returns>[ContextMenu] The context menu to add to a control.</returns>
        private ContextMenu BuildContextMenu()
        {
            MenuItem miNewAsset = new MenuItem("New Asset", NewAsset);

            ContextMenu cm = new ContextMenu(new MenuItem[] { miNewAsset });
            
            return cm;
        }

        /// <summary>
        /// GetAssetChildren
        /// Populates the various sub-domains for an asset.
        /// </summary>
        /// <param name="CurrentAsset">[AMSServiceRef.Asset] The asset object whole sub-domains
        /// are retrieved.</param>
        /// <returns>[TreeNode[]] An array of TreeNodes representing the sub-domains.</returns>
        private TreeNode[] GetAssetChildren(AMSServiceRef.Asset CurrentAsset)
        {
            if (CurrentAsset.Purchases == null)
                CurrentAsset.Purchases = new List<AMSServiceRef.PurchaseData>();
            TreeNode tnpurch = new TreeNode("Purchases", GetPurchChildren(CurrentAsset.Purchases));

            if (CurrentAsset.Schedules == null)
                CurrentAsset.Schedules = new List<AMSServiceRef.ScheduleData>();
            TreeNode tnsched = new TreeNode("Scheduled Maintenance", GetSchedChildren(CurrentAsset.Schedules));

            if (CurrentAsset.Services == null)
                CurrentAsset.Services = new List<AMSServiceRef.ServiceData>();
            TreeNode tnserv = new TreeNode("Service Records", GetServChildren(CurrentAsset.Services));

            if (CurrentAsset.Warranties == null)
                CurrentAsset.Warranties = new List<AMSServiceRef.WarrantyData>();
            TreeNode tnwarr = new TreeNode("Warranties", GetWarrChildren(CurrentAsset.Warranties));

            TreeNode[] nodes = new TreeNode[] { tnpurch, tnsched, tnserv, tnwarr };
            return nodes;
        }

        /// <summary>
        /// GetPurchChildren
        /// Creates a TreeNode array representing all the purchases in the given List.
        /// </summary>
        /// <param name="Purchases">[List<AMSServiceRef.PurchaseData>] The List of Purchase objects.</param>
        /// <returns>[TreeNode[]] An array of TreeNodes representing the purchase records.</returns>
        private TreeNode[] GetPurchChildren(List<AMSServiceRef.PurchaseData> Purchases)
        {
            TreeNode[] nodes = new TreeNode[Purchases.Count];

            for (int i = 0; i < Purchases.Count; i++)
            {
                AMSServiceRef.PurchaseData p = Purchases[i];
                TreeNode tn = new TreeNode(p.Store + " " + p.Date.ToShortDateString());
                tn.Tag = p;
                nodes[i] = tn;
            }

            return nodes;
        }

        /// <summary>
        /// GetSchedChildren
        /// Creates a TreeNode array representing all the schedules in the given List.
        /// </summary>
        /// <param name="Schedules">[List<AMSServiceRef.ScheduleData>] The List of Schedule objects.</param>
        /// <returns>[TreeNode[]] An array of TreeNodes representing the schedule records.</returns>
        private TreeNode[] GetSchedChildren(List<AMSServiceRef.ScheduleData> Schedules)
        {
            TreeNode[] nodes = new TreeNode[Schedules.Count];

            for (int i = 0; i < Schedules.Count; i++)
            {
                AMSServiceRef.ScheduleData s = Schedules[i];
                TreeNode tn = new TreeNode(s.Title);
                tn.Tag = s;
                nodes[i] = tn;
            }

            return nodes;
        }

        /// <summary>
        /// GetServChildren
        /// Creates a TreeNode array representing all the services in the given List.
        /// </summary>
        /// <param name="Services">[List<AMSServiceRef.ServiceData>] The List of Service objects.</param>
        /// <returns>[TreeNode[]] An array of TreeNodes representing the service records.</returns>
        private TreeNode[] GetServChildren(List<AMSServiceRef.ServiceData> Services)
        {
            TreeNode[] nodes = new TreeNode[Services.Count];

            for (int i = 0; i < Services.Count; i++)
            {
                AMSServiceRef.ServiceData s = Services[i];
                TreeNode tn = new TreeNode(s.Title + " " + s.Date.ToShortDateString());
                tn.Tag = s;
                nodes[i] = tn;
            }

            return nodes;
        }

        /// <summary>
        /// GetWarrChildren
        /// Creates a TreeNode array representing all the warranties in the given List.
        /// </summary>
        /// <param name="Warranties">[List<AMSServiceRef.WarrantyData>] The List of Warranty objects.</param>
        /// <returns>[TreeNode[]] An array of TreeNodes representing the warranty records.</returns>
        private TreeNode[] GetWarrChildren(List<AMSServiceRef.WarrantyData> Warranties)
        {
            TreeNode[] nodes = new TreeNode[Warranties.Count];

            for (int i = 0; i < Warranties.Count; i++)
            {
                AMSServiceRef.WarrantyData w = Warranties[i];
                TreeNode tn = new TreeNode(w.Type + " " + w.Start.ToShortDateString());
                tn.Tag = w;
                nodes[i] = tn;
            }

            return nodes;
        }

        /// <summary>
        /// NewAsset
        /// Instantiates a new AMSServiceRef.Asset object and send it back to frmMain to show the
        /// frmAssets form.  This method is only called by the ContextMenu, which is currently not used.
        /// </summary>
        /// <param name="sender">[object] The object calling this method (likely tvAssets).</param>
        /// <param name="e">[EventArgs] The standard event arguments for a Click event.</param>
        private void NewAsset(object sender, EventArgs e)
        {
            AMSServiceRef.Asset a = new AMSServiceRef.Asset();
            a.Owner = _user;
            _returnobj(a);
        }

        /// <summary>
        /// tvAssets_DoubleClick
        /// Event handler that fires when the user double-clicks the tree view.
        /// </summary>
        /// <param name="sender">[object] The object calling this method (tvAssets).</param>
        /// <param name="e">[EventArgs] The standard event arguments for a DoubleClick event.</param>
        private void tvAssets_DoubleClick(object sender, EventArgs e)
        {
            _returnobj(((TreeView)sender).SelectedNode.Tag);
        }

        /// <summary>
        /// tvAssets_MouseDown
        /// This event handler is used with the BeforeCollapse and BeforeExpand event handlers
        /// to prevent the treeview from expanding or collapsing when it is double-clicked.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tvAssets_MouseDown(object sender, MouseEventArgs e)
        {
            int delta = (int)DateTime.Now.Subtract(_lastMouseDown).TotalMilliseconds;
            _preventExpand = (delta < SystemInformation.DoubleClickTime);
            _lastMouseDown = DateTime.Now;
        }

        private void tvAssets_BeforeCollapse(object sender, TreeViewCancelEventArgs e)
        {
            e.Cancel = _preventExpand;
            _preventExpand = false;
        }

        private void tvAssets_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            e.Cancel = _preventExpand;
            _preventExpand = false;
        }
    }
}
